import re

from django import http
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View
from users.models import User
from django.db import DatabaseError
from django.contrib.auth import login, authenticate
from meiduo_mall.utils.response_code import RETCODE
from django_redis import get_redis_connection


class RegisterView(View):
    """用户注册"""

    def get(self, request):
        """提供用户注册页面"""
        return render(request, "register.html")

    def post(self, request):
        """实现用户注册业务逻辑"""
        # 接收参数，表单参数
        username = request.POST.get('username')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        mobile = request.POST.get("mobile")
        sms_code_client = request.POST.get("sms_code")
        allow = request.POST.get('allow')

        # 校验参数: 前后端的校验需要分开，避免恶意用户越过前端逻辑发请求，
        # 要保证后端的安全，前后端的校验逻辑相同
        # 判断参数是否齐全：all([列表])：会去校验列表中的元素是否为空，只要有一个为空，返回false
        if not all([username, password, password2, mobile, allow]):
            return http.HttpResponseForbidden("缺少必传参数")
        # 判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden("请输入5-20个字符的用户名")
        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden('请输入8-20位的密码')
        # 判断两次密码是否一致
        if password != password2:
            return http.HttpResponseForbidden('两次输入的密码不一致')
        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('请输入正确的手机号码')

        # 判断短信验证码是否输入正确
        redis_conn = get_redis_connection('verify_code')
        sms_code_server = redis_conn.get('sms_%s' % mobile)
        if sms_code_server is None:
            return render(request, 'register.html', {'sms_code_errmsg': '短信验证码已失效'})
        if sms_code_client != sms_code_server.decode():
            return render(request, 'register.html', {'sms_code_errmsg': '输入验证码有误'})

        # 判断是否勾选用户协议
        if allow != 'on':
            return http.HttpResponseForbidden('请勾选用户协议')

        # 保存注册数据，是注册业务的核心
        try:
            user = User.objects.create_user(username=username, password=password, mobile=mobile)
        except DatabaseError:
            return render(request, 'register.html', {"register_errmsg": '注册失败'})

        # 实行状态保持
        login(request, user)

        # 响应结果
        # contents:index(主命名空间:子命名空间)，使用reverse反向解析
        return redirect(reverse("contents:index"))


class UsernameCountView(View):
    """判断用户名是否重复注册"""

    def get(self, request, username):
        """
        :param username: 用户名
        :return: JSON
        """
        # 主体业务逻辑：使用username查询对应的记录的条数
        # filter()返回的是满足条件的结果集，
        count = User.objects.filter(username=username).count()
        # 响应结果
        return http.JsonResponse({"code": RETCODE.OK, "errmsg": 'ok', "count": count})


class MobileCountView(View):
    """判断手机号是否重复注册"""

    def get(self, request, mobile):
        """
        :param mobile: 手机号
        :return: JSON
        """
        # 主体业务逻辑：使用mobile查询对应的记录的条数
        # filter()返回的是满足条件的结果集，
        count = User.objects.filter(mobile=mobile).count()
        # 响应结果
        return http.JsonResponse({"code": RETCODE.OK, "errmsg": 'ok', "count": count})


class LoginView(View):
    """用户登录"""

    def get(self, request):
        """提供用户登录界面"""
        return render(request, 'login.html')

    def post(self, request):
        """实现用户登录逻辑"""
        # 接收参数
        username = request.POST.get("username")
        password = request.POST.get("password")
        remembered = request.POST.get("remembered")

        # 校验参数
        if not all([username, password]):
            return http.HttpResponseForbidden("缺少必传参数")
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseForbidden("请输入正确的用户名或手机号")
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.HttpResponseForbidden("密码最少8位,最长20位")

        # 认证用户：使用账号查询用户是否存在，如果用户存在，再校验密码是否正确
        user = authenticate(username=username, password=password)
        if user is None:
            return render(request, 'login.html', {'account_errmsg': '账号或密码错误'})

        # 状态保持
        login(request, user)
        # 使用 remembered 来确定状态保持的周期（实现记住登录）
        if remembered != 'on':
            # 没有记住登录：状态保持在浏览器结束后销毁
            request.session.set_expiry(0)   # 单位是秒
        else:
            # 记住登录：状态保持周期为两周：默认两周
            request.session.set_expiry(None)

        # 响应结果
        return redirect(reverse('contents:index'))
